<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Three.js 相机切换与模型自适应</title>
    <style>
        body { 
            margin: 0; 
            overflow: hidden; 
            font-family: Arial, sans-serif;
        }
        #container { 
            position: relative; 
            width: 100vw; 
            height: 100vh; 
        }
        #ui {
            position: absolute;
            top: 10px;
            left: 10px;
            background: rgba(0,0,0,0.7);
            color: white;
            padding: 10px;
            border-radius: 5px;
            z-index: 100;
        }
        button {
            background: #4CAF50;
            border: none;
            color: white;
            padding: 8px 16px;
            margin: 5px;
            border-radius: 4px;
            cursor: pointer;
        }
        button:hover {
            background: #45a049;
        }
    </style>
</head>
<body>
    <div id="container">
        <div id="ui">
            <button id="switchBtn">切换相机 (当前: 透视)</button>
            <button id="fitBtn">适应视图</button>
            <div id="info"></div>
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/three@0.132.2/build/three.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.132.2/examples/js/controls/OrbitControls.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.132.2/examples/js/loaders/GLTFLoader.js"></script>
    
    <script>
        // 1. 初始化场景
        const scene = new THREE.Scene();
        scene.background = new THREE.Color(0x333333);
        
        // 2. 相机和渲染器设置
        let camera, renderer, controls;
        let currentCameraType = 'perspective';
        
        // 3. 模型容器
        const model = new THREE.Group();
        scene.add(model);
        
        // 4. 添加光源
        const light1 = new THREE.DirectionalLight(0xffffff, 1);
        light1.position.set(1, 1, 1);
        scene.add(light1);
        
        const light2 = new THREE.AmbientLight(0x404040);
        scene.add(light2);
        
        // 5. 初始化函数
        function init() {
            // 创建渲染器
            renderer = new THREE.WebGLRenderer({ antialias: true });
            renderer.setSize(window.innerWidth, window.innerHeight);
            renderer.setPixelRatio(window.devicePixelRatio);
            document.getElementById('container').appendChild(renderer.domElement);
            
            // 初始为透视相机
            createPerspectiveCamera();
            createControls();
            
            // 添加测试模型
            addTestModel();
            
            // 事件监听
            window.addEventListener('resize', onWindowResize);
            document.getElementById('switchBtn').addEventListener('click', switchCamera);
            document.getElementById('fitBtn').addEventListener('click', fitModelToViewport);
            
            // 开始动画循环
            animate();
        }
        
        // 6. 创建透视相机
        function createPerspectiveCamera() {
            camera = new THREE.PerspectiveCamera(
                45, 
                window.innerWidth / window.innerHeight, 
                0.1, 
                1000
            );
            currentCameraType = 'perspective';
            updateUI();
        }
        
        // 7. 创建正交相机
        function createOrthographicCamera() {
            const aspect = window.innerWidth / window.innerHeight;
            const bbox = new THREE.Box3().setFromObject(model);
            const size = bbox.getSize(new THREE.Vector3());
            const maxDim = Math.max(size.x, size.y, size.z);
            
            camera = new THREE.OrthographicCamera(
                -maxDim * aspect / 2, // left
                maxDim * aspect / 2,  // right
                maxDim / 2,           // top
                -maxDim / 2,          // bottom
                0.1,                  // near
                maxDim * 10           // far
            );
            currentCameraType = 'orthographic';
            updateUI();
        }
        
        // 8. 创建控制器
        function createControls() {
            controls = new THREE.OrbitControls(camera, renderer.domElement);
            controls.enableDamping = true;
            controls.dampingFactor = 0.05;
            
            // 根据相机类型设置不同参数
            if (currentCameraType === 'orthographic') {
                controls.zoomSpeed = 2.0;
                controls.minZoom = 0.1;
                controls.maxZoom = 5;
            } else {
                controls.minDistance = 1;
                controls.maxDistance = 100;
            }
        }
        
        // 9. 相机切换函数
        function switchCamera() {
            const oldTarget = controls.target.clone();
            
            if (currentCameraType === 'perspective') {
                createOrthographicCamera();
            } else {
                createPerspectiveCamera();
            }
            
            // 保持原目标位置
            controls.target.copy(oldTarget);
            controls.object = camera;
            controls.update();
            
            fitModelToViewport();
        }
        
        // 10. 模型自适应函数
        function fitModelToViewport() {
            if (model.children.length === 0) return;
            
            const bbox = new THREE.Box3().setFromObject(model);
            if (bbox.isEmpty()) return;
            
            const size = bbox.getSize(new THREE.Vector3());
            const center = bbox.getCenter(new THREE.Vector3());
            const maxDim = Math.max(size.x, size.y, size.z);
            const aspect = window.innerWidth / window.innerHeight;
            
            // 透视相机逻辑
            if (camera.isPerspectiveCamera) {
                const fovRad = camera.fov * (Math.PI / 180);
                const distance = maxDim / (2 * Math.tan(fovRad / 2)) * 1.5;
                
                camera.position.set(
                    center.x, 
                    center.y, 
                    center.z + distance
                );
                camera.near = maxDim * 0.01;
                camera.far = maxDim * 100;
            } 
            // 正交相机逻辑
            else {
                const zoomFactor = maxDim * 1.5;
                camera.left = -zoomFactor * aspect / 2;
                camera.right = zoomFactor * aspect / 2;
                camera.top = zoomFactor / 2;
                camera.bottom = -zoomFactor / 2;
                camera.near = -maxDim * 10;
                camera.far = maxDim * 10;
                camera.zoom = 1;
                
                camera.position.set(
                    center.x,
                    center.y,
                    center.z + maxDim * 2
                );
            }
            
            camera.lookAt(center);
            controls.target.copy(center);
            controls.update();
            camera.updateProjectionMatrix();
            
            updateInfo();
        }
        
        // 11. 窗口大小调整
        function onWindowResize() {
            const aspect = window.innerWidth / window.innerHeight;
            camera.aspect = aspect;
            
            if (camera.isOrthographicCamera) {
                const bbox = new THREE.Box3().setFromObject(model);
                const size = bbox.getSize(new THREE.Vector3());
                const maxDim = Math.max(size.x, size.y, size.z);
                const zoomFactor = maxDim * 1.5;
                
                camera.left = -zoomFactor * aspect / 2;
                camera.right = zoomFactor * aspect / 2;
                camera.top = zoomFactor / 2;
                camera.bottom = -zoomFactor / 2;
            }
            
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        }
        
        // 12. 添加测试模型
        function addTestModel() {
            // 创建一个测试模型（实际使用时可以替换为GLTF加载）
            const geometry = new THREE.BoxGeometry(2, 2, 2);
            const material = new THREE.MeshStandardMaterial({ 
                color: 0x00aaff,
                metalness: 0.5,
                roughness: 0.1
            });
            const cube = new THREE.Mesh(geometry, material);
            model.add(cube);
            
            // 添加坐标轴辅助
            const axesHelper = new THREE.AxesHelper(5);
            scene.add(axesHelper);
            
            fitModelToViewport();
        }
        
        // 13. 更新UI显示
        function updateUI() {
            document.getElementById('switchBtn').textContent = 
                `切换相机 (当前: ${currentCameraType === 'perspective' ? '透视' : '正交'})`;
            updateInfo();
        }
        
        function updateInfo() {
            const info = `模型尺寸: ${getModelSize().join(' × ')}`;
            document.getElementById('info').textContent = info;
        }
        
        function getModelSize() {
            const bbox = new THREE.Box3().setFromObject(model);
            const size = bbox.getSize(new THREE.Vector3());
            return [size.x.toFixed(2), size.y.toFixed(2), size.z.toFixed(2)];
        }
        
        // 14. 动画循环
        function animate() {
            requestAnimationFrame(animate);
            controls.update();
            renderer.render(scene, camera);
        }
        
        // 启动
        init();
    </script>
</body>
</html>